﻿using OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEditor;
using UnityEngine;
using static Aliyun.OSS.DeleteObjectsResult;

public class ModelOptimize
{
    static List<string> GetSelectedFilesWithType(Type type)
    {
        List<string> list = new List<string>();
        UnityEngine.Object[] objs = Selection.GetFiltered(typeof(object), SelectionMode.DeepAssets);
        if (objs.Length > 0)
        {
            for (int i = 0; i < objs.Length; i++)
            {
                if (objs[i].GetType() != type)
                    continue;
                string path = AssetDatabase.GetAssetPath(objs[i]);
                list.Add(path);
            }
        }
        
        return list;
    }

    static List<string> GetSelectedFilesWithExtension(params string[] extensions)
    {
        List<string> list = new List<string>();
        UnityEngine.Object[] selectedObjects = Selection.GetFiltered(typeof(object), SelectionMode.DeepAssets);

        foreach (var selectedObject in selectedObjects)
        {
            //Debug.Log($"selectedObject:{selectedObject}");
            string path = AssetDatabase.GetAssetPath(selectedObject);
            if (!string.IsNullOrEmpty(path))
            {
                foreach (var extension in extensions)
                {
                    if (path.EndsWith(extension))
                        list.Add(path);
                }
            }
        }
        return list;
    }

    #region animation
    static List<string> GetSelectedAnimFiles()
    {
        return GetSelectedFilesWithType(typeof(AnimationClip));
    }

    static int num = 4;   //压缩精度

    [MenuItem("Tools/Zhan/Optimize Animation Files")]
    public static void OptimizeAnim()
    {
        List<string> list_anims = GetSelectedAnimFiles();
        CompressAnim(list_anims, false,false);
    }
    [MenuItem("Tools/Zhan/Optimize Animation Files Skip Small Value")]
    public static void OptimizeAnimSkipSmallValue()
    {
        List<string> list_anims = GetSelectedAnimFiles();
        CompressAnim(list_anims, false, true);
    }
    [MenuItem("Tools/Zhan/Optimize Animation Files Remove Scale Curve")]
    public static void OptimizeAnimRemoveScaleCurve()
    {
        List<string> list_anims = GetSelectedAnimFiles();
        CompressAnim(list_anims, true, false);
    }
    public static void CompressAnim(List<string> list_anims,bool removeScaleCurve,bool skipSmallValue)
    {
        if (list_anims.Count > 0)
        {
            for (int i = 0; i < list_anims.Count; i++)
            {
                string path = list_anims[i];

                if (!File.Exists(path))
                    continue;

                if (removeScaleCurve)
                {
                    AnimationClip theAnimation = AssetDatabase.LoadAssetAtPath<AnimationClip>(path);
                    //Debug.Log($"process anim:{path} , {theAnimation != null}");
                    foreach (EditorCurveBinding theCurveBinding in AnimationUtility.GetCurveBindings(theAnimation))
                    {
                        string name = theCurveBinding.propertyName.ToLower();
                        if (name.Contains("scale"))
                        {
                            AnimationUtility.SetEditorCurve(theAnimation, theCurveBinding, null);
                            Debug.Log($"process remove anim scale curve:{path}");
                        }
                    }
                }

                EditorUtility.DisplayProgressBar("CompressAnim", path + " Compressing...", ((float)i / list_anims.Count));
                string[] strs = File.ReadAllLines(path);
                if (strs == null)
                {
                    continue;
                }
                Debug.Log($"CompressAnim 处理：{path}");
                File.Delete(path);

                FileStream fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite);
                StreamWriter sw = new StreamWriter(fs);
                sw.Flush();
                sw.BaseStream.Seek(0, SeekOrigin.Begin);
                for (int j = 0; j < strs.Length; j++)
                {
                    if (strs[j].Contains("time"))
                    {
                        string[] txts = strs[j].Split(':');
                        if (txts != null)
                        {
                            if (txts[1].Contains(".") && (txts[1].Length - txts[1].IndexOf('.') - 1) >= num)
                            {
                                txts[1] = GetConvertFloatStr(txts[1], skipSmallValue);

                                strs[j] = txts[0] + ": " + txts[1];
                            }
                        }
                    }
                    if (strs[j].Contains("fileID"))
                    {
                        //skip file 
                    }
                    else  if (strs[j].Contains("value") || strs[j].Contains("inSlope") || strs[j].Contains("outSlope") || strs[j].Contains("inWeight") || strs[j].Contains("outWeight"))
                    {
                        strs[j].Trim();
                       
                        int frontindex = strs[j].IndexOf('{');
                        int behindindex = strs[j].IndexOf('}');

                        if (frontindex < 0)
                        { 
                            frontindex = strs[j].IndexOf(':');
                            behindindex = strs[j].Length - 1;
                         }
                        string beginstr = strs[j].Substring(0, frontindex);

                        int length = behindindex - frontindex - 1;
                        if (length < 0)
                        {
                            Debug.LogError($"error line:{strs[j]}");
                            continue;
                        }
                        string str = strs[j].Substring(frontindex + 1, length);
                        if (str != null)
                        {
                            if (str.Contains(','))
                            {
                                string[] txts = str.Split(',');
                                string tt_new = null;
                                bool changed = false;
                                for (int k = 0; k < txts.Length; k++)
                                {
                                    string[] newstr = txts[k].Split(':');
                                    if (newstr[1].Contains(".") && (newstr[1].Length - newstr[1].IndexOf('.') - 1) >= num)
                                    {
                                        newstr[1] = GetConvertFloatStr(newstr[1], skipSmallValue);
                                        changed = true;
                                    }
                                    tt_new += newstr[0] + ": " + newstr[1] + (k == txts.Length - 1 ? "" : ",");

                                }
                                if(changed)
                                    strs[j] = beginstr + "{" + tt_new + "}";
                            }
                            else
                            {
                                if (str.Contains(".") && (str.Length - str.IndexOf('.') - 1) >= num)
                                {
                                    str = GetConvertFloatStr(str, skipSmallValue);
                                  
                                    strs[j] = beginstr + ": " + str;
                                }
                            }

                        }
                    }
                    sw.WriteLine(strs[j]);
                }
                sw.Flush();
                sw.Close();
            }
            EditorUtility.ClearProgressBar();
            Resources.UnloadUnusedAssets();
            AssetDatabase.SaveAssets();
            list_anims.Clear();
            GC.Collect();

        }
        else
        {
            Debug.Log($"请选择包含动画文件的文件夹");
            return;
        }
    }

    static string GetConvertFloatStr(string str, bool skip0)
    {
        str = str.Trim();
        string ret = str;

        float originalNum = float.Parse(str);

        string tempStr = originalNum.ToString("f" + num);
        if (Math.Abs(float.Parse(tempStr)) <= 0)
        {
            if (Math.Abs(originalNum) > 0)
            {
                if (str.Contains('e') || str.Contains('E'))
                {
                    str = str.Replace('E', 'e');
                    int eIndex = str.IndexOf('e');
                    string f = str.Substring(0, eIndex);
                    f = GetConvertFloatStr(f, skip0);
                    ret = f + str.Substring(eIndex);
                }
                else
                {
                    if (skip0)
                    {
                        ret = "0";
                    }
                    else
                    {
                        //保留到原数字的第一个不是零的数
                        StringBuilder res = new StringBuilder();
                        for (int i = 0; i < str.Length; i++)
                        {
                            res.Append(str[i]);
                            //Debug.Log($"res add {str[i]} to:{res.ToString()}");
                            if (str[i] != '.' && str[i] != '0' && str[i] != '-')
                            {
                                break;
                            }
                        }
                        ret = res.ToString();
                    }
                }
            }
            else
            {
                ret = "0";
            }
        }
        else
        {
            ret = tempStr;
        }
        return ret;
    }

    #endregion

    #region FBX
    static List<string> GetSelectedFBXFiles()
    {
        return GetSelectedFilesWithExtension(".fbx", ".FBX");
    }

    [MenuItem("Tools/Zhan/Optimize FBX Files")]
    public static void OptimizeFBXs()
    {
        List<string> list = GetSelectedFBXFiles();

        Debug.Log("OptimizeFBXs: " + list.Count);

        foreach (var path in list)
        {
            ModelImporter importer = AssetImporter.GetAtPath(path) as ModelImporter;
            if (importer != null)
            {
                bool changed = false;
                if (importer.isReadable)
                {
                    // 关闭读/写标志
                    importer.isReadable = false; 
                    Debug.Log("Read/Write flag disabled for " + path);
                    changed = true;
                }
                if (importer.animationCompression != ModelImporterAnimationCompression.Optimal)
                {
                    importer.animationCompression = ModelImporterAnimationCompression.Optimal;
                    changed = true;
                    Debug.Log("animationCompression Optimal for " + path);
                }
                if (!importer.optimizeGameObjects)
                {
                    // 设置动画压缩方式为Optimal
                    importer.optimizeGameObjects = true;
                    Debug.Log("optimizeGameObjects enable for " + path);
                    changed = true;
                }
                if(changed)
                    importer.SaveAndReimport();
            }
            else
            {
                Debug.LogWarning("Failed to get ModelImporter for " + path);
            }
        }
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
    }


    #endregion

    #region FBX
    static List<string> GetSelectedPrefabFiles()
    {
        return GetSelectedFilesWithExtension(".prefab");
    }

    [MenuItem("Tools/Zhan/Optimize Prefab Files")]
    public static void OptimizePrefabs()
    {
        List<string> list = GetSelectedPrefabFiles();

        Debug.Log("OptimizePrefabs: " + list.Count);

        foreach (var path in list)
        {
            var prefabRoot = AssetDatabase.LoadAssetAtPath<GameObject>(path);
            SkinnedMeshRenderer[] skinnedRenderers = prefabRoot.GetComponentsInChildren<SkinnedMeshRenderer>(true);

            bool changed = false;
            foreach (SkinnedMeshRenderer renderer in skinnedRenderers)
            {
                // 关闭Skinned Motion Vectors属性
                renderer.skinnedMotionVectors = false;
                changed = true;
            }
            if (changed)
            {
                // 标记Prefab为已修改
                EditorUtility.SetDirty(prefabRoot);
                Debug.Log($"Set prefab SkinnedMeshRenderer.skinnedMotionVectors false");
            }
        }
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
    }


    #endregion
}
